const ipc = require("electron").ipcRenderer;
const BrowserWindow = require("electron").remote.BrowserWindow;
const path = require("path");
var fs = require("fs");
var tar = require("tar");
var Client = require("ssh2-sftp-client");
const Core = require(path.join(__dirname, "./src/core"));
const Common = require(path.join(__dirname, "./src/common"));
const util = require(path.join(__dirname, "./src/util"));
const config = require(path.join(__dirname, "./config"));

const DEPLOY_COMMAND = {
  PACK_BACK: "PACK_BACK",
  DEPLOY_BACK: "DEPLOY_BACK",
  EXTRACT_BACK: "EXTRACT_BACK",
  EXTRACT_FORE: "EXTRACT_FORE",
  PACK_FORE: "PACK_FORE",
  DEPLOY_FORE: "DEPLOY_FORE"
};
let $Game = {};
let storage = Common.getLocalStorage();
let projectIndex = storage["projectIndex"];
let mClient = new Client();

let fromWindow = null;
ipc.on("init", function(event, fromWindowId) {
  fromWindow = BrowserWindow.fromId(fromWindowId);
  initConnect();
});

ipc.on("task", function(event, cmd, params) {
  switch (cmd) {
    case DEPLOY_COMMAND.PACK_BACK:
      allUpdataBack();
      break;
    case DEPLOY_COMMAND.PACK_FORE:
      allUpdataFore();
      break;
    case "single-fore":
      singleFore();
      break;
    case "check":
      checkErlangEnv();
      break;
    case "start":
      startServer();
      break;
    case "stop":
      stopServer();
      break;
    case "fore-repo":
      initForeRepo();
      break;
    case "ssh":
      writeSsh(params);
      break;
    case "del-fore-repo":
      delForeRepo();
      break;
    case "localstorage":
      storage = Common.getLocalStorage();
      break;
    case "del-dst":
      delDst();
      break;
    case "repo-history":
      repoHistory();
      break;
    case "roll-back":
      rollBack(params);
      break;
    case "servicing":
      servicing();
      break;
  }
});
ipc.on("close", function() {
  Core.conn.end();
  mClient.end().then(() => {
    window.close();
  });
});
//发送接口
function send(cmd, code) {
  fromWindow.webContents.send("task-msg", cmd, code);
}
//初始化
function initConnect() {
  //连接shell
  let project = storage["projects"][projectIndex];
  Core.connect(project)
    .then(() => {
      send("ssh", 1);
      checkErlangEnv();
      send("init");
    })
    .catch(() => {
      send("ssh", -1);
    });
  //连接sftp
  mClient
    .connect({
      host: project.host,
      port: project.port || 22,
      password: project.password,
      user: project.username
    })
    .then(() => {
      ftpIsConnect = true;
      send("ftp", 1);
    })
    .catch(() => {
      send("ftp", -1);
    });
}

//------------------------------更新后台---------------------------------

function allUpdataBack() {
  packBack()
    .then(() => {
      send(DEPLOY_COMMAND.PACK_BACK, 1);
      return uplodBack();
    })
    .then(() => {
      //传输完成
      send(DEPLOY_COMMAND.DEPLOY_BACK, 1);
      return extractBack();
    })
    .then(() => {
      send(DEPLOY_COMMAND.EXTRACT_BACK, 1);
    })
    .catch(() => {
      send("back-fail");
    });
}

function allUpdataFore() {
  packFore()
    .then(() => {
      send(DEPLOY_COMMAND.PACK_FORE, 1);
      return uplodFore();
    })
    .then(() => {
      //传输完成
      send(DEPLOY_COMMAND.DEPLOY_FORE, 1);
      return extractFore();
    })
    .then(() => {
      send(DEPLOY_COMMAND.EXTRACT_FORE, 1);
    })
    .catch(() => {
      send("fore-fail");
    });
}
//仅传输dst
function singleFore() {
  send(DEPLOY_COMMAND.PACK_FORE, 1);
  uplodFore()
    .then(() => {
      //传输完成
      send(DEPLOY_COMMAND.DEPLOY_FORE, 1);
      return extractFore();
    })
    .then(() => {
      send(DEPLOY_COMMAND.EXTRACT_FORE, 1);
    })
    .catch(() => {
      send("fore-fail");
    });
}
/**
 * 将后台app目录
 */
function packBack() {
  let project = storage["projects"][projectIndex];
  return new Promise((resolve, reject) => {
    tar
      .c(
        {
          gzip: true,
          cwd: path.resolve(project.localWorkDir, config.back_pack_dir),
          file: path.resolve(project.localWorkDir, config.back_dist_file_name)
        },
        [config.back_pack_target_dir]
      )
      .then(() => {
        resolve();
      })
      .catch(() => {
        reject();
      });
  });
}
/**
 * 将后台打包文件传输到服务器
 */
function uplodBack() {
  let project = storage["projects"][projectIndex];
  return new Promise((resolve, reject) => {
    mClient
      .put(
        path.resolve(project.localWorkDir, config.back_dist_file_name),
        `${project.remoteWorkDir}/${config.back_pack_dir}/${config.back_dist_file_name}`
      )
      .then(() => {
        resolve();
      })
      .catch(() => {
        reject();
      });
  });
}

//解压服务器后台文件
function extractBack() {
  let project = storage["projects"][projectIndex];
  return new Promise((resolve, reject) => {
    Core.conn.exec(
      `cd ${project.remoteWorkDir}/${config.back_pack_dir} && rm -rf ${config.back_pack_target_dir} && tar -zxf ${config.back_dist_file_name}`,
      function(err, stream) {
        streamWork(resolve, reject, stream);
      }
    );
  });
}

//------------------------------更新前台---------------------------------

function packFore() {
  let project = storage["projects"][projectIndex];
  return new Promise((resolve, reject) => {
    tar
      .c(
        {
          gzip: true,
          cwd: path.resolve(project.localWorkDir, config.fore_pack_dir),
          file: path.resolve(project.localWorkDir, config.fore_dist_file_name)
        },
        [config.fore_pack_target_dir]
      )
      .then(() => {
        resolve();
      })
      .catch(() => {
        reject();
      });
  });
}
/**
 * 将后台打包文件传输到服务器
 */
function uplodFore() {
  let project = storage["projects"][projectIndex];
  return new Promise((resolve, reject) => {
    mClient
      .put(
        path.resolve(project.localWorkDir, config.fore_dist_file_name),
        `${project.remoteWorkDir}/${config.fore_pack_dir}/${config.fore_dist_file_name}`
      )
      .then(() => {
        resolve();
      })
      .catch(() => {
        reject();
      });
  });
}

//解压服务器前台文件
function extractFore() {
  let project = storage["projects"][projectIndex];
  return new Promise((resolve, reject) => {
    Core.conn.exec(
      `cd ${project.remoteWorkDir}/${config.fore_pack_dir} && rm -rf ${config.fore_pack_target_dir} && tar -zxf ${config.fore_dist_file_name}`,
      function(err, stream) {
        streamWork(resolve, reject, stream);
      }
    );
  });
}
//删除服务器前台dst下的内容
function delDst() {
  let project = storage["projects"][projectIndex];
  new Promise((resolve, reject) => {
    Core.conn.exec(
      `rm -rf ${project.remoteWorkDir}/${config.fore_pack_dir}${config.fore_pack_target_dir}/*`,
      function(err, stream) {
        streamWork(resolve, reject, stream);
      }
    );
  })
    .then(() => {
      send("del-dst");
    })
    .catch(err => {
      send("del-dst", err);
    });
}

function checkErlangEnv() {
  if ($Game.pid) {
    send("pid", $Game.pid);
    return;
  }
  Core.getPid().then(data => {
    let pid = util.getPid(data, "erlang");
    $Game.pid = pid;
    send("pid", pid);
  });
}
//启动游戏
function startServer() {
  if ($Game.pid) {
    send("alreadyrun");
    return;
  }
  let project = storage["projects"][projectIndex];
  let cm = `cd ${project.remoteWorkDir}/pi/back/boot/ && sh ${project.startScript ||
    "start.sh"}`;
  new Promise((resolve, reject) => {
    Core.conn.exec(cm, (error, stream) => {
      streamWork(resolve, reject, stream);
    });
  })
    .then(() => {
      checkErlangEnv();
      send("start", "ok");
    })
    .catch(() => {
      send("start", "error");
    });
}
//关闭游戏
function stopServer() {
  if ($Game.pid) {
    Core.stopProcess($Game.pid)
      .then(() => {
        send("stop", "ok");
        $Game.pid = null;
      })
      .catch(() => {
        send("stop", "error");
      });
  } else {
    send("not-run");
  }
}
//游戏维护中
function servicing(){

}

function streamWork(resolve, reject, stream) {
  let stdout = "";
  stream
    .on("close", function(code, signal) {
      resolve(stdout);
    })
    .on("data", function(data) {
      stdout += data;
    })
    .stderr.on("data", function(data) {
      stdout += data;
    });
}

// git 差异更新（不涉及服务器端环境搭建）
/**
 * 1. 创建远端纯仓库
 * 2. 本地仓库初始化
 * 3. 本地commit， push -> HOOK -> remote copy new file
 * 4. 重启游戏
 */
//------------------------------初始化仓库---------------------------------

//获取提交历史
function repoHistory() {
  let repoGit = `${config.git_dir}${config.fore_git_repo}.git`;
  let project = storage["projects"][projectIndex];
  new Promise((resolve, reject) => {
    Core.conn.exec(
      `
    cd ${repoGit} && git log --pretty=oneline
    `,
      (err, stream) => {
        streamWork(resolve, reject, stream);
      }
    );
  }).then(res => {
    send("repo-history", res);
  });
}

//版本回退
function rollBack(commitId) {
  let repo = `${config.git_dir}${config.fore_git_repo}`;
  let repoGit = `${config.git_dir}${config.fore_git_repo}.git`;
  let project = storage["projects"][projectIndex];
  let cm = `"cp -ru ${repo}/* ${project.remoteWorkDir}/${config.fore_pack_dir}${config.fore_pack_target_dir}"`;
  new Promise((resolve, reject) => {
    Core.conn.exec(
      `
    cd ${repo} && git reset --hard ${commitId} && rm -rf ${project.remoteWorkDir}/${config.fore_pack_dir}${config.fore_pack_target_dir}/*
    `,
      (err, stream) => {
        streamWork(resolve, reject, stream);
      }
    );
  })
    .then(res => {
      send("roll-back", res);
      return new Promise((resolve, reject) => {
        Core.conn.exec(`sh ${repo}/copy.sh`, (err, stream) => {
          streamWork(resolve, reject, stream);
        });
      });
    })
    .then(res => {
      send("roll-back-cp", res);
    });
}
//创建 fore-repo 和 fore-repo.git
function initForeRepo() {
  let repo = `${config.git_dir}${config.fore_git_repo}`;
  let repoGit = `${config.git_dir}${config.fore_git_repo}.git`;
  let project = storage["projects"][projectIndex];
  new Promise((resolve, reject) => {
    Core.conn.exec(
      `
    mkdir -p ${config.git_dir} ${repo} ${repoGit} &&
    cd ${repo} && git init && git remote add origin ssh://${project.username}@127.0.0.1:${project.port}${repoGit} &&
    cd ${repoGit} && git init --bare
    `,
      (err, stream) => {
        streamWork(resolve, reject, stream);
      }
    );
  })
    .then(stdout => {
      send("repo", stdout);
      return initHook();
    })
    .then(() => {
      send("repo-hook");
      return writeHook();
    })
    .then(() => {
      let cm = `chmod +x ${repoGit}/hooks/post-receive ${repo}/copy.sh`;
      Core.conn.exec(cm, (err, stream) => {
        if (err) send("repo-hook", err);
      });
    })
    .catch(err => {
      send("repo-hook", err);
      send("repo", err);
    });
}

//初始化目录权限以及将主机的pub文件复制到 authorized_keys
function initSsh() {
  return new Promise((resolve, reject) => {
    Core.conn.exec(
      `
    chmod 700 ~/.ssh &&
    cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys &&
    chmod 600 ~/.ssh/authorized_keys`,
      (err, stream) => {
        streamWork(resolve, reject, stream);
      }
    );
  });
}
//将公钥写至authorized_keys
function writeSsh(params) {
  if (!params.initSsh) {
    initSsh().then(() => {
      new Promise((resolve, reject) => {
        Core.conn.exec(
          `
        echo ${params.key} >> ~/.ssh/authorized_keys
        `,
          (err, stream) => {
            streamWork(resolve, reject, stream);
          }
        );
      })
        .then(stdout => {
          send("ssh");
        })
        .catch(err => {
          send("ssh", err);
        });
    });
  } else {
    new Promise((resolve, reject) => {
      Core.conn.exec(
        `
      echo ${params.key} >> ~/.ssh/authorized_keys
      `,
        (err, stream) => {
          streamWork(resolve, reject, stream);
        }
      );
    })
      .then(stdout => {
        send("ssh", stdout);
      })
      .catch(err => {
        send("ssh", err);
      });
  }
}

//删除远端前台git仓库
function delForeRepo() {
  let repo = `${config.git_dir}${config.fore_git_repo}`;
  let repoGit = `${config.git_dir}${config.fore_git_repo}.git`;
  new Promise((resolve, reject) => {
    Core.conn.exec(`rm -rf ${repo} ${repoGit}`, (err, stream) => {
      streamWork(resolve, reject, stream);
    });
  })
    .then(stdout => {
      send("del-fore-repo", "");
    })
    .catch(err => {
      send("del-fore-repo", err);
    });
}

//writeHook
function writeHook() {
  let project = storage["projects"][projectIndex];
  let repo = `${config.git_dir}${config.fore_git_repo}/*`;
  let repoGit = `${config.git_dir}${config.fore_git_repo}.git`;
  let cm = `"cp -ru ${repo} ${project.remoteWorkDir}/${config.fore_pack_dir}${config.fore_pack_target_dir}/"`;
  return new Promise((resolve, reject) => {
    Core.conn.exec(
      `echo ${cm} >> ${repoGit}/hooks/post-receive && echo ${cm} >> ${config.git_dir}${config.fore_git_repo}/copy.sh`,
      (err, stream) => {
        streamWork(resolve, reject, stream);
      }
    );
  });
}
//初始化hook
function initHook() {
  let repoGit = `${config.git_dir}${config.fore_git_repo}.git`;
  return mClient.put(
    path.resolve(__dirname, "scripts", "post-receive"),
    `${repoGit}/hooks/post-receive`
  );
}
